#include "message_kernel_impl.h"
#include "process/message_process_impl.h"
#include "sync/message_sync_impl.h"
#include <core/system/thread_wrapper.h>
#include <core/sharedata/login_data.h>
#include <qbprotocol/include/rdMessage.h>
#include <qbnet/source/network_service_impl.h>

#ifndef WIN32
#include <arpa/inet.h>
#endif

#include <assert.h>

namespace qb
{
	CMessageKernel::CMessageKernel()
        : m_spMessageProcess(NULL)
        , m_spMessageSync(NULL)
        , m_spNetworkService(NULL)
	{
	}

	CMessageKernel::~CMessageKernel()
	{
	}

	STDMETHODIMP_(int32_t) CMessageKernel::Create(THIS_ INetworkService* ins, IMessageSync* sync, IMessageProcess* process)
	{
        m_spNetworkService = ins;
        m_spMessageSync = sync;
        m_spMessageProcess = process;

        AttachModules();

		return 0;
	}

	STDMETHODIMP_(int32_t) CMessageKernel::Destory(THIS_)
	{
        CloseConnect(loginData::instance().ConnectID());

        DetachModules();

        RemoveObserver<IMessageKernelObserver>(m_observers);

		return 0;
	}

    STDMETHODIMP_(int32_t) CMessageKernel::RegisterMessageKernelObserver(THIS_ IMessageKernelObserver* observer)
    {
        return RegisterObserver<IMessageKernelObserver>(observer,m_observers);
    }

    STDMETHODIMP_(int32_t) CMessageKernel::DeRegisterMessageKernelObserver(THIS_ IMessageKernelObserver* observer)
    {
        return DeRegisterObserver<IMessageKernelObserver>(observer,m_observers);
    }

    STDMETHODIMP_(int32_t) CMessageKernel::NotifyNetStatus(THIS_ qb::NetStatus status, short retcode)
    {
		BList<IMessageKernelObserver*>::iterator iter = m_observers.begin();
		for_each_list(m_observers, iter, (iter++)->first->OnRecvNetStatus(status, retcode));

        return 0;
    }

    STDMETHODIMP_(int32_t) CMessageKernel::RegisterNetwork(THIS_ int32_t connect_id)
    {
		QB_CHECK_RETURN_INT_ASSERT1(m_spNetworkService);

        return (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->RegisterNetworkServiceObserver(connect_id, this);
    }

    STDMETHODIMP_(int32_t) CMessageKernel::DeRegisterNetwork(THIS_ int32_t connect_id)
    {
		QB_CHECK_RETURN_INT_ASSERT1(m_spNetworkService);

		return (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->DeRegisterNetworkServiceObserver(connect_id, this);
    }

    STDMETHODIMP_(int32_t) CMessageKernel::CreateConnect(THIS_)
    {
		QB_CHECK_RETURN_INT1(m_spNetworkService);

		int32_t connectid = (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->CreateSocket(kSocketTcp);
        RegisterNetwork(connectid);

		return connectid;
    }

    STDMETHODIMP_(int32_t) CMessageKernel::Connect(THIS_ int32_t connect_id, const char* ip, uint32_t port)
    {
		QB_CHECK_RETURN_INT1(ip);

		if (-1 == connect_id)
		{
			if (m_spMessageSync)
			{
                (static_cast<CMessageSyncImpl*>(m_spMessageSync))->PushMessage(0, 0, kLoginConnect, new int16_t(kConnectConnectFailed));
			}

			return -1;
		}

		if (-1 == (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->Connect(connect_id, ip, port))
		{
			log_error("can not connect ip:[%s], port:[%d]", ip, port);
			//	Disconnect();

				// 通过MessageSync通知主线程，连接失败
			if (m_spMessageSync)
			{
                (static_cast<CMessageSyncImpl*>(m_spMessageSync))->PushMessage(0, 0, kLoginConnect, new int16_t(kConnectConnectFailed));
			}
			return -1;
		}

		return 0;
    }

    STDMETHODIMP_(int32_t) CMessageKernel::Send(THIS_ int32_t connect_id, const char* buff, uint32_t bytes)
    {
		QB_CHECK_RETURN_INT1(m_spNetworkService);

		return (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->Send(connect_id, buff, bytes);
    }

    STDMETHODIMP_(int32_t) CMessageKernel::CloseConnect(THIS_ int32_t connect_id)
    {
		QB_CHECK_RETURN_INT1(m_spNetworkService);

        DeRegisterNetwork(connect_id);

		if (-1 != connect_id)
		{
            (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->Disconnect(connect_id);
            (static_cast<CNetworkServiceImpl*>(m_spNetworkService))->DestorySocket(connect_id);
            loginData::instance().ConnectID() = -1;
		}

		return 0;
    }

    void CMessageKernel::AttachModules()
    {
        if (m_spMessageSync)
        {
            (static_cast<CMessageSyncImpl*>(m_spMessageSync))->RegisterMessageObserverTUS(this);
        }
    }

    void CMessageKernel::DetachModules()
    {
		if (m_spMessageSync)
		{
			(static_cast<CMessageSyncImpl*>(m_spMessageSync))->DeRegisterMessageObserverTUS(this);
		}

        m_spMessageProcess = NULL;
        m_spMessageSync = NULL;
        m_spNetworkService = NULL;
    }

	STDMETHODIMP_(bool) CMessageKernel::OnConnect(THIS_ int32_t connect_id, int32_t error_id)
	{
		if (m_spMessageSync && connect_id == loginData::instance().ConnectID())
		{
            (static_cast<CMessageSyncImpl*>(m_spMessageSync))->PushMessage(NULL, 0, kLoginConnect, new int32_t(error_id));
			return true;
		}

		return false;
	}

    STDMETHODIMP_(void) CMessageKernel::OnReceive(THIS_ int32_t connect_id, MESSAGE_SHARED_PTR msp)
    {
        QB_CHECK_RETURN_VOID1(m_spMessageProcess);

        if (connect_id == loginData::instance().ConnectID())
        {
            (static_cast<CMessageProcessImpl*>(m_spMessageProcess))->PushNetMessage(msp);
        }
    }

    STDMETHODIMP_(void) CMessageKernel::OnReceive2(THIS_ int32_t connect_id, const char* buff, uint32_t bytes)
    {
        QB_CHECK_RETURN_VOID1(m_spMessageSync);

        if (connect_id == loginData::instance().ConnectID())
        {
            (static_cast<CMessageSyncImpl*>(m_spMessageSync))->PushMessage(buff, bytes);
        }
    }

    STDMETHODIMP_(void) CMessageKernel::OnNetData(char* pRecvData, int nDataLen)
    {
        if (m_spMessageProcess)
        {
            m_spMessageProcess->PushMainThreadMessage(pRecvData, nDataLen);
        }

        BList<IMessageKernelObserver*>::iterator iter = m_observers.begin();
        for_each_list(m_observers,iter,(iter++)->first->OnRecvMsg(pRecvData, nDataLen));
    }
}
